import json
import logging
import re
import allure
from jsonpath import jsonpath
from typing import List, Dict, Union
from utils.global_variable_tool import gv

logger = logging.getLogger(__name__)

class AssertionErrorWithDetail(AssertionError):
    """带详细错误信息的断言异常"""
    def __init__(self, field, expect, actual):
        self.message = f"断言失败: 字段 [{field}]\n期望值 -> {expect}\n实际值 -> {actual}"
        super().__init__(self.message)

class AssertionTool:
    def __init__(self, response):
        self.response = response
        self.gv = gv
        try:
            self.response_data = response.json()
        except json.JSONDecodeError:
            self.response_data = response.text

    def _extract_value(self, field_path: str):
        """使用 JSONPath 提取字段值"""
        if field_path.startswith("$"):
            result = jsonpath(self.response_data, field_path)
            return result[0] if result else None
        return self.response_data.get(field_path)

    def _compare_values(self, actual, expect, compare_type: str) -> bool:
        """根据比较类型执行断言"""
        compare_type = compare_type.lower()

        if compare_type == "equals":
            return actual == expect
        elif compare_type == "contains":
            return str(expect) in str(actual)
        elif compare_type == "regex":
            return bool(re.match(expect, str(actual)))
        elif compare_type == "type":
            return isinstance(actual, eval(expect))
        elif compare_type == "length":
            return len(actual) == int(expect)
        else:
            raise ValueError(f"不支持的比较类型: {compare_type}")

    def validate(
        self,
        assert_fields: List[Union[str, Dict]],
        save_globals: Union[str, Dict[str, str]] = None
    ):
        """
        执行断言并保存全局变量
        :param assert_fields: 断言规则列表，支持字符串简写或字典详细配置
        :param save_globals: 需要保存到全局变量的字段映射
        """
        with allure.step("响应断言"):
            # 保存全局变量
            if save_globals:
                if isinstance(save_globals, str):
                    # 解析字符串为字典
                    save_globals = dict(item.split('=') for item in save_globals.split(';') if item)
                for var_name, field_path in save_globals.items():
                    value = self._extract_value(field_path)
                    gv.set_var(var_name, value)

            # 获取全局变量

            global_vars = gv.getVars()
            logger.info("当前全局变量：{}".format(global_vars))

            # 执行断言
            for rule in assert_fields:
                if isinstance(rule, str):
                    # 简写模式：$.msg=成功
                    field_path, expect = rule.split("=", 1)
                    compare_type = "equals"
                else:
                    # 详细模式
                    field_path = rule["field"]
                    expect = rule.get("expect")
                    compare_type = rule.get("type", "equals")

                actual = self._extract_value(field_path)

                # 记录到Allure报告
                allure.attach(
                    name="断言详情",
                    body=f"字段路径: {field_path}\n期望值: {expect}\n实际值: {actual}",
                    attachment_type=allure.attachment_type.TEXT
                )

                # 执行比较
                if not self._compare_values(actual, expect, compare_type):
                    raise AssertionErrorWithDetail(field_path, expect, actual)

            logger.info("所有断言验证通过")